#pragma once
#include "CGIPrefix.h"
#include "CGIAccess.h"
#include "Runtime/Base/Object.h"
#include "Runtime/Math/IntPoint.h"
#include "Runtime/Math/IntVector.h"
#include "Runtime/Math/Color.h"

namespace Alice{
	class CGICommandListImmediate;
	enum class EClearBinding
	{
		ENoneBound, //no clear color associated with this target.  Target will not do hardware clears on most platforms
		EColorBound, //target has a clear color bound.  Clears will use the bound color, and do hardware clears.
		EDepthStencilBound, //target has a depthstencil value bound.  Clears will use the bound values and do hardware clears.
	};
	VkFormat UEToVkBufferFormat(EVertexElementType Type);
	// Defines which channel is valid for each pixel format
	enum class EPixelFormatChannelFlags : uint8
	{
		R = 1 << 0,
		G = 1 << 1,
		B = 1 << 2,
		A = 1 << 3,
		RG = R | G,
		RGB = R | G | B,
		RGBA = R | G | B | A,

		None = 0,
	};
	ENUM_CLASS_FLAGS(EPixelFormatChannelFlags);

	enum class EPixelFormatCapabilities : uint32
	{
		None             = 0,
		Texture1D        = 1ull << 1,
		Texture2D        = 1ull << 2,
		Texture3D        = 1ull << 3,
		TextureCube      = 1ull << 4,
		RenderTarget     = 1ull << 5,
		DepthStencil     = 1ull << 6,
		TextureMipmaps   = 1ull << 7,
		TextureLoad      = 1ull << 8,
		TextureSample    = 1ull << 9,
		TextureGather    = 1ull << 10,
		TextureAtomics   = 1ull << 11,
		TextureBlendable = 1ull << 12,
		TextureStore     = 1ull << 13,

		Buffer           = 1ull << 14,
		VertexBuffer     = 1ull << 15,
		IndexBuffer      = 1ull << 16,
		BufferLoad       = 1ull << 17,
		BufferStore      = 1ull << 18,
		BufferAtomics    = 1ull << 19,

		UAV              = 1ull << 20,
		TypedUAVLoad     = 1ull << 21,
		TypedUAVStore    = 1ull << 22,

		TextureFilterable = 1ull << 23,

		AnyTexture       = Texture1D | Texture2D | Texture3D | TextureCube,

		AllTextureFlags  = AnyTexture | RenderTarget | DepthStencil | TextureMipmaps | TextureLoad | TextureSample | TextureGather | TextureAtomics | TextureBlendable | TextureStore,
		AllBufferFlags   = Buffer | VertexBuffer | IndexBuffer | BufferLoad | BufferStore | BufferAtomics,
		AllUAVFlags      = UAV | TypedUAVLoad | TypedUAVStore,

		AllFlags         = AllTextureFlags | AllBufferFlags | AllUAVFlags
	};
	ENUM_CLASS_FLAGS(EPixelFormatCapabilities);
	/** 
	* Information about a pixel format. The majority of this structure is valid after static init, however RHI does keep
	* some state in here that is initialized by that module and should not be used by general use programs that don't
	* have RHI (so noted in comments).
	*/
	struct FPixelFormatInfo
	{
		FPixelFormatInfo() = delete;
		FPixelFormatInfo(
			EPixelFormat InUnrealFormat,
			const TCHAR* InName,
			int32 InBlockSizeX,
			int32 InBlockSizeY,
			int32 InBlockSizeZ,
			int32 InBlockBytes,
			int32 InNumComponents,
			bool  InSupported);

		const TCHAR*				Name;
		EPixelFormat				UnrealFormat;
		int32						BlockSizeX;
		int32						BlockSizeY;
		int32						BlockSizeZ;
		int32						BlockBytes;
		int32						NumComponents;

		/** Per platform cabilities for the format (initialized by RHI module - invalid otherwise) */
		EPixelFormatCapabilities	Capabilities = EPixelFormatCapabilities::None;

		/** Platform specific converted format (initialized by RHI module - invalid otherwise) */
		uint32						PlatformFormat{ 0 };

		/** Whether the texture format is supported on the current platform/ rendering combination */
		uint8						Supported : 1;

		// If false, 32 bit float is assumed (initialized by RHI module - invalid otherwise)
		uint8						bIs24BitUnormDepthStencil : 1;
		
		/** 
		* Get 2D/3D image/texture size in bytes. This is for storage of the encoded image data, and does not adjust
		* for any GPU alignment/padding constraints. It is also not valid for tiled or packed mip tails (i.e. cooked mips 
		* for consoles). Only use these when you know you're working with bog standard textures/images in block based pixel formats.
		*/
		uint64 Get2DImageSizeInBytes(uint32 InWidth, uint32 InHeight) const;
		uint64 Get2DTextureMipSizeInBytes(uint32 InTextureWidth, uint32 InTextureHeight, uint32 InMipIndex) const;
		uint64 Get2DTextureSizeInBytes(uint32 InTextureWidth, uint32 InTextureHeight, uint32 InMipCount) const;
		uint64 Get3DImageSizeInBytes(uint32 InWidth, uint32 InHeight, uint32 InDepth) const;
		uint64 Get3DTextureMipSizeInBytes(uint32 InTextureWidth, uint32 InTextureHeight, uint32 InTextureDepth, uint32 InMipIndex) const;
		uint64 Get3DTextureSizeInBytes(uint32 InTextureWidth, uint32 InTextureHeight, uint32 InTextureDepth, uint32 InMipCount) const;
		
		/**
		* Get the number of compressed blocks necessary to hold the given dimensions.
		*/
		uint64 GetBlockCountForWidth(uint32 InWidth) const;
		uint64 GetBlockCountForHeight(uint32 InHeight) const;
	};
	extern FPixelFormatInfo GPixelFormats[EPixelFormat::PF_NUM];		// Maps members of EPixelFormat to a FPixelFormatInfo describing the format.
	CGIAccess CGIGetDefaultResourceState(ETextureCreateFlags InUsage, bool bInHasInitialData);
	struct FClearValueBinding
	{
		struct DSVAlue
		{
			float Depth;
			uint32 Stencil;
		};

		FClearValueBinding()
			: ColorBinding(EClearBinding::EColorBound)
		{
			Value.Color[0] = 0.0f;
			Value.Color[1] = 0.0f;
			Value.Color[2] = 0.0f;
			Value.Color[3] = 0.0f;
		}

		FClearValueBinding(EClearBinding NoBinding)
			: ColorBinding(NoBinding)
		{
			Value.Color[0] = 0.0f;
			Value.Color[1] = 0.0f;
			Value.Color[2] = 0.0f;
			Value.Color[3] = 0.0f;

			Value.DSValue.Depth = 0.0f;
			Value.DSValue.Stencil = 0;
		}

		explicit FClearValueBinding(const FLinearColor& InClearColor)
			: ColorBinding(EClearBinding::EColorBound)
		{
			Value.Color[0] = InClearColor.R;
			Value.Color[1] = InClearColor.G;
			Value.Color[2] = InClearColor.B;
			Value.Color[3] = InClearColor.A;
		}

		explicit FClearValueBinding(float DepthClearValue, uint32 StencilClearValue = 0)
			: ColorBinding(EClearBinding::EDepthStencilBound)
		{
			Value.DSValue.Depth = DepthClearValue;
			Value.DSValue.Stencil = StencilClearValue;
		}

		FLinearColor GetClearColor() const
		{
			return FLinearColor(Value.Color[0], Value.Color[1], Value.Color[2], Value.Color[3]);
		}

		void GetDepthStencil(float& OutDepth, uint32& OutStencil) const
		{
			OutDepth = Value.DSValue.Depth;
			OutStencil = Value.DSValue.Stencil;
		}

		bool operator==(const FClearValueBinding& Other) const
		{
			if (ColorBinding == Other.ColorBinding)
			{
				if (ColorBinding == EClearBinding::EColorBound)
				{
					return
						Value.Color[0] == Other.Value.Color[0] &&
						Value.Color[1] == Other.Value.Color[1] &&
						Value.Color[2] == Other.Value.Color[2] &&
						Value.Color[3] == Other.Value.Color[3];

				}
				if (ColorBinding == EClearBinding::EDepthStencilBound)
				{
					return
						Value.DSValue.Depth == Other.Value.DSValue.Depth &&
						Value.DSValue.Stencil == Other.Value.DSValue.Stencil;
				}
				return true;
			}
			return false;
		}

		EClearBinding ColorBinding;

		union ClearValueType
		{
			float Color[4];
			DSVAlue DSValue;
		} Value;

		// common clear values
		static const FClearValueBinding None;
		static const FClearValueBinding Black;
		static const FClearValueBinding BlackMaxAlpha;
		static const FClearValueBinding White;
		static const FClearValueBinding Transparent;
		static const FClearValueBinding DepthOne;
		static const FClearValueBinding DepthZero;
		static const FClearValueBinding DepthNear;
		static const FClearValueBinding DepthFar;	
		static const FClearValueBinding Green;
		static const FClearValueBinding DefaultNormal8Bit;
	};
	/** Descriptor used to create a texture resource */
	struct CGITextureDesc
	{
		CGITextureDesc() = default;

		CGITextureDesc(const CGITextureDesc& Other)
		{
			*this = Other;
		}

		CGITextureDesc(ETextureDimension InDimension)
			: Dimension(InDimension)
		{}

		CGITextureDesc(
			ETextureDimension   InDimension
			, ETextureCreateFlags InFlags
			, EPixelFormat        InFormat
			, FClearValueBinding  InClearValue
			, IntPoint            InExtent
			, uint16              InDepth
			, uint16              InArraySize
			, uint8               InNumMips
			, uint8               InNumSamples
			, uint32              InExtData
			)
			: Flags     (InFlags     )
			, ClearValue(InClearValue)
			, ExtData   (InExtData   )
			, Extent    (InExtent    )
			, Depth     (InDepth     )
			, ArraySize (InArraySize )
			, NumMips   (InNumMips   )
			, NumSamples(InNumSamples)
			, Dimension (InDimension )
			, Format    (InFormat    )
		{}

		bool operator == (const CGITextureDesc& Other) const
		{
			return Dimension  == Other.Dimension
				&& Flags      == Other.Flags
				&& Format     == Other.Format
				&& UAVFormat  == Other.UAVFormat
				&& Extent     == Other.Extent
				&& Depth      == Other.Depth
				&& ArraySize  == Other.ArraySize
				&& NumMips    == Other.NumMips
				&& NumSamples == Other.NumSamples
				&& FastVRAMPercentage == Other.FastVRAMPercentage
				&& ClearValue == Other.ClearValue
				&& ExtData    == Other.ExtData;
		}

		bool operator != (const CGITextureDesc& Other) const
		{
			return !(*this == Other);
		}

		CGITextureDesc& operator=(const CGITextureDesc& Other)
		{
			Dimension			= Other.Dimension;
			Flags				= Other.Flags;
			Format				= Other.Format;
			UAVFormat			= Other.UAVFormat;
			Extent				= Other.Extent;
			Depth				= Other.Depth;
			ArraySize			= Other.ArraySize;
			NumMips				= Other.NumMips;
			NumSamples			= Other.NumSamples;
			ClearValue			= Other.ClearValue;
			ExtData				= Other.ExtData;
			FastVRAMPercentage	= Other.FastVRAMPercentage;

			return *this;
		}

		bool IsTexture2D() const
		{
			return Dimension == ETextureDimension::Texture2D || Dimension == ETextureDimension::Texture2DArray;
		}

		bool IsTexture3D() const
		{
			return Dimension == ETextureDimension::Texture3D;
		}

		bool IsTextureCube() const
		{
			return Dimension == ETextureDimension::TextureCube || Dimension == ETextureDimension::TextureCubeArray;
		}

		bool IsTextureArray() const
		{
			return Dimension == ETextureDimension::Texture2DArray || Dimension == ETextureDimension::TextureCubeArray;
		}

		bool IsMipChain() const
		{
			return NumMips > 1;
		}

		bool IsMultisample() const
		{
			return NumSamples > 1;
		}

		IntVector GetSize() const
		{
			return IntVector(Extent.X, Extent.Y, Depth);
		}

		void Reset()
		{
			// Usually we don't want to propagate MSAA samples.
			NumSamples = 1;

			// Remove UAV flag for textures that don't need it (some formats are incompatible).
			Flags |= ETextureCreateFlags::RenderTargetable;
			Flags &= ~(ETextureCreateFlags::UAV | ETextureCreateFlags::ResolveTargetable | ETextureCreateFlags::DepthStencilResolveTarget | ETextureCreateFlags::Memoryless);
		}

		/** Returns whether this descriptor conforms to requirements. */
		bool IsValid() const
		{
			return CGITextureDesc::Validate(*this, /* Name = */ TEXT(""), /* bFatal = */ false);
		}

		/** Texture flags passed on to RHI texture. */
		ETextureCreateFlags Flags = ETextureCreateFlags::None;

		/** Clear value to use when fast-clearing the texture. */
		FClearValueBinding ClearValue;

		/** Platform-specific additional data. Used for offline processed textures on some platforms. */
		uint32 ExtData = 0;

		/** Extent of the texture in x and y. */
		IntPoint Extent = IntPoint(1, 1);

		/** Depth of the texture if the dimension is 3D. */
		uint16 Depth = 1;

		/** The number of array elements in the texture. (Keep at 1 if dimension is 3D). */
		uint16 ArraySize = 1;

		/** Number of mips in the texture mip-map chain. */
		uint8 NumMips = 1;

		/** Number of samples in the texture. >1 for MSAA. */
		uint8 NumSamples = 1;

		/** Texture dimension to use when creating the RHI texture. */
		ETextureDimension Dimension = ETextureDimension::Texture2D;

		/** Pixel format used to create RHI texture. */
		EPixelFormat Format = EPixelFormat::PF_Unknown;

		/** Texture format used when creating the UAV. PF_Unknown means to use the default one (same as Format). */
		EPixelFormat UAVFormat = EPixelFormat::PF_Unknown;

		/** Resource memory percentage which should be allocated onto fast VRAM (hint-only). (encoding into 8bits, 0..255 -> 0%..100%) */
		uint8 FastVRAMPercentage = 0xFF;

		/** Check the validity. */
		static bool CheckValidity(const CGITextureDesc& Desc, const TCHAR* Name)
		{
			return CGITextureDesc::Validate(Desc, Name, /* bFatal = */ true);
		}

		/**
		 * Returns an estimated total memory size the described texture will occupy in GPU memory.
		 * This is an estimate because it only considers the dimensions / format etc of the texture, 
		 * not any specifics about platform texture layout.
		 * 
		 * To get a true measure of a texture resource for the current running platform RHI, use RHICalcTexturePlatformSize().
		 * 
		 * @param FirstMipIndex - the index of the most detailed mip to consider in the memory size calculation. Must be < NumMips and <= LastMipIndex.
		 * @param LastMipIndex  - the index of the least detailed mip to consider in the memory size calculation. Must be < NumMips and >= FirstMipIndex.
		 */
		uint64 CalcMemorySizeEstimate(uint32 FirstMipIndex, uint32 LastMipIndex) const;

		uint64 CalcMemorySizeEstimate(uint32 FirstMipIndex = 0) const
		{
			return CalcMemorySizeEstimate(FirstMipIndex, NumMips - 1);
		}

	private:
		static bool Validate(const CGITextureDesc& Desc, const TCHAR* Name, bool bFatal);
	};
	struct CGITextureCreateDesc : public CGITextureDesc
	{
		static CGITextureCreateDesc Create(const TCHAR* InDebugName, ETextureDimension InDimension)
		{
			return CGITextureCreateDesc(InDimension);
		}

		static CGITextureCreateDesc Create2D(const TCHAR* InDebugName)
		{
			return CGITextureCreateDesc(ETextureDimension::Texture2D);
		}

		static CGITextureCreateDesc Create2DArray(const TCHAR* InDebugName)
		{
			return CGITextureCreateDesc(ETextureDimension::Texture2DArray);
		}

		static CGITextureCreateDesc Create3D(const TCHAR* InDebugName)
		{
			return CGITextureCreateDesc(ETextureDimension::Texture3D);
		}

		static CGITextureCreateDesc CreateCube(const TCHAR* InDebugName)
		{
			return CGITextureCreateDesc(ETextureDimension::TextureCube);
		}

		static CGITextureCreateDesc CreateCubeArray(const TCHAR* InDebugName)
		{
			return CGITextureCreateDesc(ETextureDimension::TextureCubeArray);
		}

		static CGITextureCreateDesc Create2D(const TCHAR* DebugName, IntPoint Size, EPixelFormat Format)
		{
			return Create2D(DebugName)
				.SetExtent(Size)
				.SetFormat(Format);
		}

		static CGITextureCreateDesc Create2D(const TCHAR* DebugName, int32 SizeX, int32 SizeY, EPixelFormat Format)
		{
			return Create2D(DebugName)
				.SetExtent(SizeX, SizeY)
				.SetFormat(Format);
		}

		static CGITextureCreateDesc Create2DArray(const TCHAR* DebugName, IntPoint Size, uint16 ArraySize, EPixelFormat Format)
		{
			return Create2DArray(DebugName)
				.SetExtent(Size)
				.SetFormat(Format)
				.SetArraySize((uint16)ArraySize);
		}

		static CGITextureCreateDesc Create2DArray(const TCHAR* DebugName, int32 SizeX, int32 SizeY, int32 ArraySize, EPixelFormat Format)
		{
			return Create2DArray(DebugName)
				.SetExtent(SizeX, SizeY)
				.SetFormat(Format)
				.SetArraySize((uint16)ArraySize);
		}

		static CGITextureCreateDesc Create3D(const TCHAR* DebugName, IntVector Size, EPixelFormat Format)
		{
			return Create3D(DebugName)
				.SetExtent(Size.X, Size.Y)
				.SetDepth((uint16)Size.Z)
				.SetFormat(Format);
		}

		static CGITextureCreateDesc Create3D(const TCHAR* DebugName, int32 SizeX, int32 SizeY, int32 SizeZ, EPixelFormat Format)
		{
			return Create3D(DebugName)
				.SetExtent(SizeX, SizeY)
				.SetDepth((uint16)SizeZ)
				.SetFormat(Format);
		}

		static CGITextureCreateDesc CreateCube(const TCHAR* DebugName, uint32 Size, EPixelFormat Format)
		{
			return CreateCube(DebugName)
				.SetExtent(Size)
				.SetFormat(Format);
		}

		static CGITextureCreateDesc CreateCubeArray(const TCHAR* DebugName, uint32 Size, uint16 ArraySize, EPixelFormat Format)
		{
			return CreateCubeArray(DebugName)
				.SetExtent(Size)
				.SetFormat(Format)
				.SetArraySize((uint16)ArraySize);
		}

		CGITextureCreateDesc() = default;

		// Constructor with minimal argument set. Name and dimension are always required.
		CGITextureCreateDesc(ETextureDimension InDimension)
			: CGITextureDesc(InDimension)
		{
		}
		CGITextureCreateDesc& SetFlags(ETextureCreateFlags InFlags)               { Flags = InFlags;                          return *this; }
		CGITextureCreateDesc& AddFlags(ETextureCreateFlags InFlags)               { Flags |= InFlags;                         return *this; }
		CGITextureCreateDesc& SetClearValue(FClearValueBinding InClearValue)      { ClearValue = InClearValue;                return *this; }
		CGITextureCreateDesc& SetExtData(uint32 InExtData)                        { ExtData = InExtData;                      return *this; }
		CGITextureCreateDesc& SetExtent(const IntPoint& InExtent)                { Extent = InExtent;                        return *this; }
		CGITextureCreateDesc& SetExtent(int32 InExtentX, int32 InExtentY)         { Extent = IntPoint(InExtentX, InExtentY); return *this; }
		CGITextureCreateDesc& SetExtent(uint32 InExtent)                          { Extent = IntPoint(InExtent);             return *this; }
		CGITextureCreateDesc& SetDepth(uint16 InDepth)                            { Depth = InDepth;                          return *this; }
		CGITextureCreateDesc& SetArraySize(uint16 InArraySize)                    { ArraySize = InArraySize;                  return *this; }
		CGITextureCreateDesc& SetNumMips(uint8 InNumMips)                         { NumMips = InNumMips;                      return *this; }
		CGITextureCreateDesc& SetNumSamples(uint8 InNumSamples)                   { NumSamples = InNumSamples;                return *this; }
		CGITextureCreateDesc& SetDimension(ETextureDimension InDimension)         { Dimension = InDimension;                  return *this; }
		CGITextureCreateDesc& SetFormat(EPixelFormat InFormat)                    { Format = InFormat;                        return *this; }
		CGITextureCreateDesc& SetUAVFormat(EPixelFormat InUAVFormat)              { UAVFormat = InUAVFormat;                  return *this; }
		CGITextureCreateDesc& SetInitialState(CGIAccess InInitialState)          { InitialState = InInitialState;            return *this; }
		CGITextureCreateDesc& DetermineInititialState()                           { if (InitialState == CGIAccess::Unknown) InitialState = CGIGetDefaultResourceState(Flags, false); return *this; }
		CGITextureCreateDesc& SetFastVRAMPercentage(float In)                     { FastVRAMPercentage = uint8(MathUtils::Clamp(In, 0.f, 1.0f) * 0xFF); return *this; }
		CGITextureCreateDesc& SetClassName(const std::string& InClassName)			  { ClassName = InClassName;				   return *this; }
		CGITextureCreateDesc& SetOwnerName(const std::string& InOwnerName)			{ OwnerName = InOwnerName;                  return *this; }

		/* The RHI access state that the resource will be created in. */
		CGIAccess InitialState = CGIAccess::Unknown;

		std::string ClassName;	// The owner class of FRHITexture used for Insight asset metadata tracing
		std::string OwnerName;	// The owner name used for Insight asset metadata tracing
	};
    class CGIResource : public Object{
    public:
        CGIResource(ECGIResourceType inResourceType);
        virtual ~CGIResource();
        const ECGIResourceType mResourceType;
        uint8 mbCommitted : 1;
        uint8 mbAllowExtendLifetime : 1;
    };
    class CGIViewableResource : public CGIResource{
    public:
		CGIAccess TrackedAccess;
    	CGIViewableResource(ECGIResourceType InResourceType, CGIAccess InAccess)
			: CGIResource(InResourceType)
			, TrackedAccess(InAccess)
    	{}
    };
    class CGITexture : public CGIViewableResource{
    public:
		CGITextureDesc TextureDesc;
    	CGITexture(ECGIResourceType inResourceType):CGIViewableResource(inResourceType,CGIAccess::Unknown){}
    	CGITexture(const CGITextureCreateDesc& InDesc);
		virtual const CGITextureDesc& GetDesc() const { return TextureDesc; }
    	uint32 GetNumMips() const { return GetDesc().NumMips; }
    };
	enum class ERenderTargetActions : uint8
	{
		LoadOpMask = 2,

	#define RTACTION_MAKE_MASK(Load, Store) (((uint8)ERenderTargetLoadAction::Load << (uint8)LoadOpMask) | (uint8)ERenderTargetStoreAction::Store)

		DontLoad_DontStore =	RTACTION_MAKE_MASK(ENoAction, ENoAction),

		DontLoad_Store =		RTACTION_MAKE_MASK(ENoAction, EStore),
		Clear_Store =			RTACTION_MAKE_MASK(EClear, EStore),
		Load_Store =			RTACTION_MAKE_MASK(ELoad, EStore),

		Clear_DontStore =		RTACTION_MAKE_MASK(EClear, ENoAction),
		Load_DontStore =		RTACTION_MAKE_MASK(ELoad, ENoAction),
		Clear_Resolve =			RTACTION_MAKE_MASK(EClear, EMultisampleResolve),
		Load_Resolve =			RTACTION_MAKE_MASK(ELoad, EMultisampleResolve),

	#undef RTACTION_MAKE_MASK
	};
	enum class EDepthStencilTargetActions : uint8
	{
		DepthMask = 4,

	#define RTACTION_MAKE_MASK(Depth, Stencil) (((uint8)ERenderTargetActions::Depth << (uint8)DepthMask) | (uint8)ERenderTargetActions::Stencil)

		DontLoad_DontStore =						RTACTION_MAKE_MASK(DontLoad_DontStore, DontLoad_DontStore),
		DontLoad_StoreDepthStencil =				RTACTION_MAKE_MASK(DontLoad_Store, DontLoad_Store),
		DontLoad_StoreStencilNotDepth =				RTACTION_MAKE_MASK(DontLoad_DontStore, DontLoad_Store),
		ClearDepthStencil_StoreDepthStencil =		RTACTION_MAKE_MASK(Clear_Store, Clear_Store),
		LoadDepthStencil_StoreDepthStencil =		RTACTION_MAKE_MASK(Load_Store, Load_Store),
		LoadDepthNotStencil_StoreDepthNotStencil =	RTACTION_MAKE_MASK(Load_Store, DontLoad_DontStore),
		LoadDepthNotStencil_DontStore =				RTACTION_MAKE_MASK(Load_DontStore, DontLoad_DontStore),
		LoadDepthStencil_StoreStencilNotDepth =		RTACTION_MAKE_MASK(Load_DontStore, Load_Store),

		ClearDepthStencil_DontStoreDepthStencil =	RTACTION_MAKE_MASK(Clear_DontStore, Clear_DontStore),
		LoadDepthStencil_DontStoreDepthStencil =	RTACTION_MAKE_MASK(Load_DontStore, Load_DontStore),
		ClearDepthStencil_StoreDepthNotStencil =	RTACTION_MAKE_MASK(Clear_Store, Clear_DontStore),
		ClearDepthStencil_StoreStencilNotDepth =	RTACTION_MAKE_MASK(Clear_DontStore, Clear_Store),
		ClearDepthStencil_ResolveDepthNotStencil =	RTACTION_MAKE_MASK(Clear_Resolve, Clear_DontStore),
		ClearDepthStencil_ResolveStencilNotDepth =	RTACTION_MAKE_MASK(Clear_DontStore, Clear_Resolve),
		LoadDepthClearStencil_StoreDepthStencil  =  RTACTION_MAKE_MASK(Load_Store, Clear_Store),

		ClearStencilDontLoadDepth_StoreStencilNotDepth = RTACTION_MAKE_MASK(DontLoad_DontStore, Clear_Store),

	#undef RTACTION_MAKE_MASK
	};
	struct CGIRenderPassInfo
	{
		struct FColorEntry
		{
			CGITexture*         RenderTarget      = nullptr;
			CGITexture*         ResolveTarget     = nullptr;
			int32                ArraySlice        = -1;
			uint8                MipIndex          = 0;
			ERenderTargetActions Action            = ERenderTargetActions::DontLoad_DontStore;
		};
		FColorEntry mColorRenderTargets;
		struct FDepthStencilEntry
		{
			CGITexture*         DepthStencilTarget = nullptr;
			CGITexture*         ResolveTarget      = nullptr;
			EDepthStencilTargetActions Action       = EDepthStencilTargetActions::DontLoad_DontStore;
			//FExclusiveDepthStencil ExclusiveDepthStencil;
		};
		FDepthStencilEntry DepthStencilRenderTarget;
	};
    class CGIViewport : public CGIResource{
    public:
        CGIViewport() : CGIResource(RRT_Viewport) {}
        /**
         * Returns access to the platform-specific native resource pointer.  This is designed to be used to provide plugins with access
         * to the underlying resource and should be used very carefully or not at all.
         *
         * @return	The pointer to the native resource or NULL if it not initialized or not supported for this resource type for some reason
         */
        virtual void* GetNativeSwapChain() const { return nullptr; }
        /**
         * Returns access to the platform-specific native resource pointer to a backbuffer texture.  This is designed to be used to provide plugins with access
         * to the underlying resource and should be used very carefully or not at all.
         *
         * @return	The pointer to the native resource or NULL if it not initialized or not supported for this resource type for some reason
         */
        virtual void* GetNativeBackBufferTexture() const { return nullptr; }
        /**
         * Returns access to the platform-specific native resource pointer to a backbuffer rendertarget. This is designed to be used to provide plugins with access
         * to the underlying resource and should be used very carefully or not at all.
         *
         * @return	The pointer to the native resource or NULL if it not initialized or not supported for this resource type for some reason
         */
        virtual void* GetNativeBackBufferRT() const { return nullptr; }

        /**
         * Returns access to the platform-specific native window. This is designed to be used to provide plugins with access
         * to the underlying resource and should be used very carefully or not at all. 
         *
         * @return	The pointer to the native resource or NULL if it not initialized or not supported for this resource type for some reason.
         * AddParam could represent any additional platform-specific data (could be null).
         */
        virtual void* GetNativeWindow(void** AddParam = nullptr) const { return nullptr; }

        /**
         * Sets custom Present handler on the viewport
         */
        virtual void SetCustomPresent(class FRHICustomPresent*) {}

        /**
         * Returns currently set custom present handler.
         */
        virtual class FRHICustomPresent* GetCustomPresent() const { return nullptr; }


        /**
         * Ticks the viewport on the Game thread
         */
        virtual void Tick(float DeltaTime) {}

        virtual void WaitForFrameEventCompletion() { }

        virtual void IssueFrameEvent() { }
        void Draw( bool bShouldPresent = true );
    };
}
